#!/usr/bin/php
<?php
/**
 * This file is part of php-server-class.
 * 
 * php-server-class is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * php-server-class is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with php-server-class.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @package php-server-class
 * @author Rick Barenthin <dunst0@gmail.com>
 * @copyright Copyright (c) 2010, Rick Barenthin
 * @license http://www.gnu.org/licenses/ GNU General Public License v3
 * @version 0.0.4
 */
declare(encoding='UTF-8');


//START PHP Settings
error_reporting(E_ALL|E_STRICT);
set_time_limit(0);
ini_set('display_errors', 1);
ini_set('memory_limit', -1);
date_default_timezone_set('Europe/Berlin');
ob_implicit_flush();
//END PHP Settings


//Packet einbinden
require_once 'package-server/package.server.php';
use Server\Server;

define('HTTP_EOL', "\r\n", TRUE);
define('HTTPD_NAME', 'myPHPSever/0.0(alpha)', TRUE);


class Response
{
    protected $HTTP_STATUS = array(
        100 => '100 Continue',
        200 => '200 OK',
        201 => '201 Created',
        204 => '204 No Content',
        206 => '206 Partial Content',
        300 => '300 Multiple Choices',
        301 => '301 Moved Permanently',
        302 => '302 Found',
        303 => '303 See Other',
        304 => '304 Not Modified',
        307 => '307 Temporary Redirect',
        400 => '400 Bad Request',
        401 => '401 Unauthorized',
        403 => '403 Forbidden',
        404 => '404 Not Found',
        405 => '405 Method Not Allowed',
        406 => '406 Not Acceptable',
        408 => '408 Request Timeout',
        410 => '410 Gone',
        413 => '413 Request Entity Too Large',
        414 => '414 Request URI Too Long',
        415 => '415 Unsupported Media Type',
        416 => '416 Requested Range Not Satisfiable',
        417 => '417 Expectation Failed',
        500 => '500 Internal Server Error',
        501 => '501 Method Not Implemented',
        503 => '503 Service Unavailable',
        506 => '506 Variant Also Negotiates'
    );
    protected $Header = array();
    protected $Content = '';
    protected $Status = 100;
    
    protected $ProtocolVersion = '1.1';
    
    public function setProtocolVersion($version)
    {
        $this->ProtocolVersion = $version;
    }
    
    public function setStatus ($status)
    {
        $this->Status = $status;
    }
    
    public function addHeader($name, $value)
    {
        $this->Header[] = $name . ': ' . $value;
    }
    
    public function addContent($content)
    {
        $this->Content .= $content;
    }
    
    public function getResponse()
    {
        $response  = 'HTTP/' . $this->ProtocolVersion . ' ' . $this->HTTP_STATUS[$this->Status] . HTTP_EOL;
        $response .= implode(HTTP_EOL, $this->Header);
        $response .= HTTP_EOL;
        $response .= HTTP_EOL;
        $response .= $this->Content;
        
        return $response;
    }
}


//Request verarbeitende Funktion
function httpRequestHandler ($rawRequest)
{
    $rawRequest = preg_split("/\\r\\n/", $rawRequest);
    $REQUEST = array();
    if (preg_match('/([^ ]+) ([^ ]+) (HTTP\/[01].[0-9])/', $rawRequest[0], $matches)) {
        
        list(, $REQUEST['REQUEST_METHOD'], $REQUEST['REQUEST_URI'], $REQUEST['REQUEST_PROTOCOL']) = $matches;
        if (preg_match('/([^?]*)(?:\?([^#]*))?(?:#.*)?/', $REQUEST['REQUEST_URI'], $matches)) {
            $REQUEST['PATH'] = $matches[1];
            $REQUEST['QUERY_STRING'] = empty($matches[2]) ? '' : $matches[2];
        }

        unset($rawRequest[0]);
        
        $REQUEST['HEADERS'] = array();
        foreach ($rawRequest as $req) {
            if (preg_match('/([^:]+): (.*)/', $req, $matches))
                $REQUEST['HEADERS'][$matches[1]] = $matches[2];
        }
    }
    else
        $REQUEST = FALSE;
    
    $response = new Response();
    $response->addHeader('Server', HTTPD_NAME);
    $response->addHeader('Date', gmdate('D, d M Y H:i:s') . ' GMT');
    
    if ($REQUEST === FALSE)
        $response->setStatus(400);
    else {
        $content = 'Text';
        
        $response->setStatus(200);
        $response->addHeader('Content-Length', strlen($content));
        $response->addHeader('Content-Type', 'text/html; charset=UTF-8');
        $response->addHeader('Connection', 'close');
        $response->addContent($content);
    }
    
    return (object) array(
        'response' => $response->getResponse(),
        'keepAlive' => FALSE,
        'accessInfo' => $REQUEST['REQUEST_METHOD'] . ' "' . $REQUEST['REQUEST_URI'] . '" "UserAgent"'
    );
}


//Server erzeugen der an localhost gebunden ist und auf Port 80 lauscht
$Server = new Server ('localhost', 80);

//Debug ausgaben anschalten
$Server->enableDebugOutput();
//Reqest Terminierung auf zweimal CRLF setzen, fuer HTTP
$Server->setRequestTermination(HTTP_EOL . HTTP_EOL);
//Die anzahl der Maximalen Request bei einer KeepAlive verbindung
$Server->setMaxRequestCount(10);
//TimeOut Zeit nach dem die Verbindung getrennt wird
$Server->setKeepAliveTimeOut(60);
//Setzen der Request Verarbeitungs Funktion
//Sie bekommt uebergeben den String der den rawRequest enthaelt,
//und von ihr wird als Rueckgabewert ein object erwartet, dass die Properties
//"response"(String), "keepAlive"(bool) und "accessInfo"(String) enthaelt.
$Server->registerRequestHandler('httpRequestHandler');

//Server Starten
$Server->start();
while ( $Server->serverRunning() )
    $Server->loop(); //Auf anfragen warten und beantworten
$Server->stop();

?>